﻿using System;
using System.Collections.Generic;
using System.Data;

namespace QueryBuilder.Core.Query.SqlTypes
{
    /// <summary>
    /// 
    /// </summary>
    public class SqlTypeFactory
    {
        /// <summary>
        /// 
        /// </summary>
        public static readonly SqlType Boolean = new SqlType(DbType.Boolean);
        /// <summary>
        /// 
        /// </summary>
        public static readonly SqlType DateTime = new SqlType(DbType.DateTime);
        /// <summary>
        /// 
        /// </summary>
        private static readonly IDictionary<string, SqlType> SqlTypes = new Dictionary<string, SqlType>();
        /// <summary>
        /// 
        /// </summary>
        public static SqlType Double = new SqlType(DbType.Double);
        /// <summary>
        /// 
        /// </summary>
        public static SqlType Int32 = new SqlType(DbType.Int32);


        /// <summary>
        /// Gets the string.
        /// </summary>
        /// <param name="length">The length.</param>
        /// <returns></returns>
        public static StringSqlType GetString(int length)
        {
            return GetTypeWithLen<StringSqlType>(length, (l) => new StringSqlType(l));
        }

        /// <summary>
        /// Gets the type with len.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="length">The length.</param>
        /// <param name="createDelegate">The create delegate.</param>
        /// <returns></returns>
        private static T GetTypeWithLen<T>(int length, Func<int, SqlType> createDelegate)
            where T : SqlType
        {
            SqlType type;
            string keyForLengthBased = GetKeyForLengthBased(typeof (T).Name, length);
            if (!SqlTypes.TryGetValue(keyForLengthBased, out type))
            {
                type = createDelegate(length);
                SqlTypes.Add(keyForLengthBased, type);
            }
            return (T) type;
        }

        /// <summary>
        /// Gets the key for length based.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="length">The length.</param>
        /// <returns></returns>
        private static string GetKeyForLengthBased(string name, int length)
        {
            return string.Concat(new object[] {name, "(", length, ")"});
        }
    }
}